//
//  DBTable.m
//  iDent
//
//  Created by Marius Corega on 8/5/09.
//  Copyright 2009 Marius Corega. All rights reserved.
//

#import "DBTable.h"
#import <CoreFoundation/CoreFoundation.h>

@implementation DBTable

@synthesize isLoadingVersion;
@synthesize _elemente;


-(void) lockEnded:(NSString*) elementID
{
		if(!lockedElements) lockedElements = [[NSMutableArray alloc] init];
		if(![self iLockedElementWithID:elementID])[lockedElements addObject:elementID];
	
}

-(id) init
{
	self = [super init];
	
	lockedElements = [[NSMutableArray alloc] init];
	isLoadingVersion = NO;
	//unlockTimer = [NSTimer timerWithTimeInterval:30.0f target:self selector:@selector(unlockTimerFireMethod:) userInfo:nil repeats:YES];
	//[[NSRunLoop currentRunLoop] addTimer:unlockTimer forMode:NSRunLoopCommonModes];	
	
	q = [[NSOperationQueue alloc] init];
	
/*	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(lockEnded)
												 name:@"LockEnded" object:nil];
	
*/	
	return self;
}

- (id)initWithXMLData: (NSData*) data tableName:(NSString*) tableName elementName:(NSString*) elementName
{
	if([self init])
	{
		_tableName = tableName;
		_elementName = elementName;
		
		NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
		[parser setDelegate:self];
		
		[parser parse];
	}
	else return nil;
	
	return self;
}

-(id) initWithURL:(NSURL*) url postDict:(NSDictionary*)dict tableName:(NSString*) tableName elementName:(NSString*) elementName
{
	self = [self init];
	
	_url = [url copy];
	_postDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
	_tableName = [tableName copy];
	_elementName = [elementName copy];
	
//	[self initWithXMLData:[self loadData] tableName:tableName elementName:elementName];
	
	return self;
}

-(id) initWithURL:(NSURL*) url postDict:(NSDictionary*)dict
{
	NSString* tn;
	
	tn = [dict objectForKey:@"tabel"];
	if(!tn) tn = @"elements";
	
	return [self initWithURL:url postDict:dict tableName:tn elementName:@"element"];
}

-(id)initWithURL:(NSURL*) url tableName:(NSString*) tableName
{
	NSMutableDictionary* postDict = [NSMutableDictionary dictionary];
	[postDict setObject:tableName forKey:@"tabel"];
	
	
	return [self initWithURL:url postDict:postDict tableName:tableName elementName:@"element"];
}

-(id) initWithServerURL:(NSURL*) url postDict:(NSDictionary*)dict
{
	
	NSMutableString* srvURL = [NSMutableString stringWithString: [url absoluteString] ];
	[srvURL appendString:@"tabel.php"];
	_serverURL = [url copy];
	
	
	return [self initWithURL:[NSURL URLWithString:srvURL] postDict:dict];
}

-(id)initWithServerURL:(NSURL*) url tableName:(NSString*) tableName
{
	NSMutableString* srvURL = [NSMutableString stringWithString: [url absoluteString] ];
	[srvURL appendString:@"tabel.php"];
	_serverURL = [url copy];

	return [self initWithURL:[NSURL URLWithString:srvURL] tableName:tableName];
}

-(id)initWithServerURL:(NSURL*) url
{
	return [self initWithServerURL:url tableName:nil];
}

- (NSData*)generateFormData:(NSDictionary*)dict
{
	NSString* boundary = [NSString stringWithString:@"_insert_some_boundary_here_"];
	NSArray* keys = [dict allKeys];
	NSMutableData* result = [[NSMutableData alloc] initWithCapacity:100];
	
	int i;
	for (i = 0; i < [keys count]; i++) 
	{
		id value = [dict valueForKey: [keys objectAtIndex: i]];
		[result appendData:[[NSString stringWithFormat:@"--%@\n", boundary] dataUsingEncoding:NSASCIIStringEncoding]];
		/*		if ([value class] == [NSString class]  )
		 {
		 [result appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\n\n", [keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
		 [result appendData:[[NSString stringWithFormat:@"%@",value] dataUsingEncoding:NSASCIIStringEncoding]];
		 
		 }
		 */
		if ([value class] == [NSURL class] && [value isFileURL])
		{
			[result appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\n", [keys objectAtIndex:i], [[value path] lastPathComponent]] dataUsingEncoding:NSASCIIStringEncoding]];
			[result appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\n\n"] dataUsingEncoding:NSASCIIStringEncoding]];
			[result appendData:[NSData dataWithContentsOfFile:[value path]]];
		}
		else
		{
			[result appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\n\n", [keys objectAtIndex:i]] dataUsingEncoding:NSASCIIStringEncoding]];
			[result appendData:[[NSString stringWithFormat:@"%@",value] dataUsingEncoding:NSASCIIStringEncoding]];
			
		}
		[result appendData:[[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]];
	}
	[result appendData:[[NSString stringWithFormat:@"--%@--\n", boundary] dataUsingEncoding:NSASCIIStringEncoding]];
	
	return [result autorelease];
}

-(NSData*) postData:(NSDictionary*) dict URL:(NSURL*) url
{
	NSURLResponse* response;
	NSError* error;	
	
	NSMutableURLRequest* post = [NSMutableURLRequest requestWithURL: url];
	
	NSMutableDictionary* pDict = [NSMutableDictionary dictionaryWithDictionary:dict];
	[pDict setObject:_tableName forKey:@"tabel"];
	
	if([pDict objectForKey:@"canEdit"]) [pDict removeObjectForKey:@"canEdit"];
	
	NSData* regData = [self generateFormData:pDict];
	
	[post setHTTPBody:regData];
	
	[post addValue: @"multipart/form-data; boundary=_insert_some_boundary_here_" forHTTPHeaderField: @"Content-Type"];
	[post setHTTPMethod: @"POST"];
	
	//[progressIndicator startAnimation:self];
	NSData* result = [NSURLConnection sendSynchronousRequest:post returningResponse:&response error:&error];
	NSLog([url absoluteString]);
	NSLog(@"%@", [[[NSString alloc] initWithData:result encoding:NSASCIIStringEncoding] autorelease]);
	//[progressIndicator stopAnimation:self];
	
	return result;
}

-(void)loadEnded: (NSData*) data
{
	if(data)
	{
		//[_elemente removeAllObjects];
		//if(parser) {[parser release]; parser = nil;}
		
		NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
		[parser setDelegate:self];
		
		[parser parse];
		[parser release];
		[_element release];
		_element = nil;
//		res = YES;
		//[data release];
	}
	
	for(NSInteger i=0; i<[_elemente count]; i++)
		if([self iLockedElementWithID:[[_elemente objectAtIndex:i] valueForKey:@"id"]])
			[[_elemente objectAtIndex:i] setValue:@"1" forKey:@"canEdit"];
		else
		{
			NSString* canEdit = [[_elemente objectAtIndex:i] objectForKey:@"time_locked"];
			NSString *val = @"1";
			
			if([canEdit boolValue]) val = @"0";
			
			
			[[_elemente objectAtIndex:i] setValue:val  forKey:@"canEdit"];
		}
	
	if (notification != nil)
	{
		[[NSNotificationCenter defaultCenter] postNotificationName:notification object:nil];
	}
}

-(NSData*)loadData 
{
	NSLog(@"dict: %@, URL: %@", _postDict, _url);
	
	
	NSData *data = [self postData:_postDict URL:_url];
	[self performSelectorOnMainThread:@selector(loadEnded:) withObject:data waitUntilDone:NO];
	
	return data;
}

-(NSData*) loadVersion
{
	NSMutableString* srvURL = [NSMutableString stringWithString: [_serverURL absoluteString] ];
	[srvURL appendString:@"versiunetabel.php"];
	
	NSData *data = [self postData:_postDict URL:[NSURL URLWithString:srvURL]];
	
	return data;
}

- (NSString *)uuid
{
	CFUUIDRef uuidRef = CFUUIDCreate(NULL);
	CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
	CFRelease(uuidRef);
	return [(NSString *)uuidStringRef autorelease];
}

-(BOOL)load
{
	BOOL res = NO;

	
	if(_elemente)
	{
		[_elemente release];
		_elemente = nil;
	}
	
	{
		NSData* data;
		
		if(isLoadingVersion) data = [self loadVersion];
		else data = [self loadData];
		
		
		if(data)
		{
			//[_elemente removeAllObjects];
			//if(parser) {[parser release]; parser = nil;}
			
			NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
			[parser setDelegate:self];
			
			[parser parse];
			[parser release];
			[_element release];
			_element = nil;
			res = YES;
			//[data release];
		}
		
	}
	/*
	else
	{
		 DBTable* tabel = [[DBTable alloc] initWithServerURL:_serverURL postDict:_postDict];
		 res  = [tabel load];
		 
		[_elemente removeAllObjects];
		
		[_elemente autorelease];
		_elemente = [[NSMutableArray alloc] initWithArray:[tabel elemente]];
		
		[tabel release];		
	}
	 */

	for(NSInteger i=0; i<[_elemente count]; i++)
		if([self iLockedElementWithID:[[_elemente objectAtIndex:i] valueForKey:@"id"]])
			[[_elemente objectAtIndex:i] setValue:@"1" forKey:@"canEdit"];
		else
		{
			NSString* canEdit = [[_elemente objectAtIndex:i] objectForKey:@"time_locked"];
			NSString *val = @"1";
			
			if([canEdit boolValue]) val = @"0";
			
			
			[[_elemente objectAtIndex:i] setValue:val  forKey:@"canEdit"];
		}
	
	return res;
}

-(void)loadSync
{
	[self load];
}

-(void)loadAsync
{
	
	if(_elemente)
	{
		[_elemente release];
		_elemente = nil;
	}
	
		NSInvocationOperation *op;
		
		if(isLoadingVersion) op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadVersion) object:nil];
		else op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadData) object:nil];
		
		
		[q addOperation: op ];
		[op release];
		
}

-(BOOL)reloadData
{

	 DBTable* tabel = [[DBTable alloc] initWithServerURL:_serverURL postDict:_postDict];
	tabel.isLoadingVersion = YES;
	BOOL res  = [tabel load];
	
	//	NSArray* elementeVechi = _elemente;
	//	_elemente = [NSMutableArray array];
	
	for(NSInteger i=0; i<[[tabel elemente] count]; i++)
	{
		NSDictionary* tabel_elem = [[tabel elemente] objectAtIndex:i];
		NSMutableDictionary* self_elem = [self elementWithID:[tabel_elem objectForKey:@"id"]];
		
		if(self_elem)
		{
			if(![[tabel_elem objectForKey:@"version"] isEqualToString:[self_elem objectForKey:@"version"]])
			{
				
				[self_elem setDictionary:[self getElementWithID:[tabel_elem objectForKey:@"id"]]];
			}
		}
		else
		{
			[_elemente addObject:[self getElementWithID:[tabel_elem objectForKey:@"id"]]];
		}
	}
	
	NSMutableArray* deSters = [NSMutableArray array];
	for(NSInteger i=0; i<[_elemente count]; i++)
	{
		NSDictionary* self_elem = [_elemente objectAtIndex:i];
		NSDictionary* tabel_elem = [tabel elementWithID:[self_elem objectForKey:@"id"]];
		
		
		if(!tabel_elem) [deSters addObject:self_elem];
		
	}	
	for(NSInteger i=0; i<[deSters count]; i++) [_elemente removeObject:[deSters objectAtIndex:i]]; 
	
	return res;
}

-(BOOL)loadForPacientWithID:(NSString*) pacientID
{
	NSMutableDictionary* dict  = _postDict;
	_postDict = [[NSMutableDictionary alloc] init];
	[_postDict setValue:pacientID forKey:@"pacientid"];
	[_postDict setValue:_tableName forKey:@"tabel"];
	
	BOOL res = [self load];
	
	[_postDict release];
	_postDict = dict;
	
	return res;
}

-(void)loadForPacientWithIDAsync:(NSString*) pacientID
{
//	NSMutableDictionary* dict  = _postDict;
	_postDict = [[NSMutableDictionary alloc] init];
	[_postDict setValue:pacientID forKey:@"pacientid"];
	[_postDict setValue:_tableName forKey:@"tabel"];
	
	[self loadAsync];
	
//	[_postDict release];
//	_postDict = dict;

}


-(void) printDict:(NSDictionary*)dict
{
	NSArray* keys = [dict allKeys];
	
	for(int i=0; i<[keys count]; i++) 
	{
		NSMutableString* str = [NSMutableString stringWithString: [keys objectAtIndex:i] ];
		
		[str appendString:@"="];
		[str appendString:[dict objectForKey:[keys objectAtIndex:i]]];
		
		NSLog(str);
	}

}

-(BOOL) setElement:(NSDictionary*) postDict
{
	NSDictionary* dict;
	NSMutableDictionary* pDict = [NSMutableDictionary dictionaryWithDictionary:postDict];
	NSString* elementID = [postDict objectForKey:@"id"];
	[pDict setObject:[self uuid] forKey:@"version"];
	
	
	if([self iLockedElementWithID:elementID])
	
	/*	
	{
		if([self lockElementWithID:elementID])
		{
	*/		
			for(int i=0;i <[_elemente count]; i++) 
			{
				dict = [_elemente objectAtIndex:i];
				if([[dict objectForKey:@"id"] isEqualToString:elementID])
				{
					
					[pDict setObject:_tableName forKey:@"tabel"];
//					[self printDict:pDict];
					NSMutableString* str = [NSMutableString stringWithString:[_serverURL absoluteString]];
					[str appendString:@"modificatabel.php"];
					NSURL* url = [NSURL URLWithString:str];
					
					[self postData:pDict URL:url];
				
				//	[self unlockElementWithID:elementID];
					
					return YES;
				}
				
			}
	/*
		}
	}
	 */
	return NO;
}

-(BOOL) setElementWithID:(NSString*) elementID value:(NSString*)value forField:(NSString*) field
{
	[[self elementWithID:elementID] setValue:value forKey:field];
	
	NSMutableDictionary* postDict = [NSMutableDictionary dictionary];
	
	[postDict setObject:elementID forKey:@"id"];
	[postDict setObject:value forKey:field];
	
	return [self setElement:postDict];
}

-(BOOL) setElementWithID:(NSString*) elementID 
{
	NSDictionary* dict;
	for(int i=0;i <[_elemente count]; i++) 
	{
		dict = [_elemente objectAtIndex:i];
		if([[dict objectForKey:@"id"] isEqualToString:elementID]) break;
	}
	
	NSMutableDictionary* postDict = [NSMutableDictionary dictionaryWithDictionary:dict];
	//[postDict setObject:_tableName forKey:@"tabel"];
	
	return [self setElement:postDict];
}

-(NSDictionary*) getElementWithID:(NSString*) elementID 
{
	NSMutableDictionary* postDict = [NSMutableDictionary dictionary];
	[postDict setObject:_tableName forKey:@"tabel"];
	[postDict setObject:elementID forKey:@"id"];

	DBTable* table = [[DBTable alloc] initWithServerURL:_serverURL postDict:postDict];
	[table load];
	
	NSString* lock = [[[table elemente] objectAtIndex:0] objectForKey:@"canEdit"];
	if([self iLockedElementWithID:elementID]) lock = @"1";
	
	[[[table elemente] objectAtIndex:0] setValue:lock forKey:@"canEdit"];
	
	NSDictionary* elem = [[table elemente] objectAtIndex:0];
	[table autorelease];
	
	return elem;
}

-(NSString*) getElementWithID:(NSString*) elementID forField:(NSString*) field
{
	return [[self getElementWithID:elementID] valueForKey:field];
}

-(NSMutableDictionary*) elementWithID:(NSString*) elementID
{
	for(NSInteger i=0; i<[_elemente count]; i++)
	{
		if([[[_elemente objectAtIndex:i] valueForKey:@"id"] isEqualToString:elementID]) return [_elemente objectAtIndex:i];
	}
	return nil;
}

-(BOOL) reloadElementWithID:(NSString*) elementID
{
	NSDictionary* dict = [self getElementWithID:elementID];
	
	for(NSInteger i=0; i<[_elemente count]; i++)
	{
		if([[[_elemente objectAtIndex:i] objectForKey:@"id"] isEqualToString:elementID])
		{
			[[_elemente objectAtIndex:i] setDictionary:dict];
			//[_elemente replaceObjectAtIndex:i withObject:dict];
			break;
		}
		
	}
	
	if(dict) return YES;
	
	return NO;
}

-(BOOL) isLocked:(NSString*) elementID
{
	if([self iLockedElementWithID:elementID]) return YES;
	
	NSString* res = [self getElementWithID:elementID forField:@"time_locked"];
	
	return (BOOL)[res intValue];
}

-(BOOL) iLockedElementWithID:(NSString*) elementID
{
	for (NSInteger i = 0; i<[lockedElements count]; i++)
	{
		if([elementID isEqualToString:[lockedElements objectAtIndex:i]]) return YES;
	}
	
	return NO;
}

-(void) lockElementWithIDAsync:(NSString*) elementID
{
	NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(lockElementWithID:) object:elementID];
	
	[q addOperation: op ];	
	[op release];
}


-(BOOL) lockElementWithID:(NSString*) elementID
{
	
	NSMutableString* srvURL = [[NSMutableString alloc] initWithString: [_serverURL absoluteString] ];
	[srvURL appendString:@"lock.php"];
	NSDictionary* dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:_tableName, elementID, @"1", [self uuid], nil]
													 forKeys:[NSArray arrayWithObjects:@"tabel", @"id", @"lock", @"version", nil]];
	
	DBTable* db = [[[DBTable alloc] initWithURL:[NSURL URLWithString:srvURL]  postDict:dict] autorelease];
	[srvURL release];
	//db.notification = @"LockEnded";
	[db load];
	
	
	NSString* res = [[[db elemente] objectAtIndex:0] valueForKey:@"result"];
	
	
	
	if([res isEqualToString:@"1"])
	{
		[self performSelectorOnMainThread:@selector(lockEnded:) withObject:elementID waitUntilDone:NO];
		
		return YES;
	}
	
	
	//return NO;
	return YES;
}

-(BOOL) unlockElementWithID:(NSString*) elementID
{
	BOOL ret = NO;
	
	if([self iLockedElementWithID:elementID])
	{
		NSMutableString* srvURL = [[NSMutableString alloc] initWithString: [_serverURL absoluteString] ];
		[srvURL appendString:@"lock.php"];
		NSDictionary* dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:_tableName, elementID, @"0", [self uuid],nil]
														 forKeys:[NSArray arrayWithObjects:@"tabel", @"id", @"lock", @"version", nil]];
		
		DBTable* db = [[[DBTable alloc] initWithURL:[NSURL URLWithString:srvURL]  postDict:dict] autorelease];
		
		[srvURL release];
		
		ret =  [db load];
		
		for(NSInteger i=0; i<[lockedElements count]; i++)
			if([elementID isEqualToString:[lockedElements objectAtIndex:i]]) { [lockedElements removeObjectAtIndex:i]; }
		
		
	}
	
	return ret;
}

-(void) unlockElements
{
	for (NSInteger i=0; i<[lockedElements count]; i++) [self unlockElementWithID:[lockedElements objectAtIndex:i]];
}

-(NSString*) addElement:(NSDictionary*) dict
{
	NSMutableString* str = [NSMutableString stringWithString:[_serverURL absoluteString]];
	[str appendString:@"adaugatabel.php"];
	NSURL* url = [NSURL URLWithString:str];
	
	NSData* result = [self postData:dict URL:url];
	
	return [[NSString alloc] initWithData:result encoding:NSASCIIStringEncoding];
}

-(NSString*) addElement
{
	return [self addElement:nil];
}

-(BOOL) removeElementWithID:(NSString*) elementID
{
	return [self setElementWithID:elementID value:@"1" forField:@"sters"];
}


- (NSArray*)elemente
{
	return _elemente;
}

-(NSDictionary*)postDict
{
	return _postDict;
}

-(void) setPostDict:(NSDictionary*) dict
{
	if(_postDict) [_postDict release];
	_postDict = [dict copy];
}

-(void)unlockTimerFireMethod:(NSTimer*)theTimer
{
//	NSDictionary* dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"tabel",nil] forKeys:[NSArray arrayWithObjects:_tableName, nil]];
	
	for(NSInteger i=0 ; i<[lockedElements count]; i++) [self lockElementWithID:[lockedElements objectAtIndex:i]];
	
	NSMutableString* srvURL = [[NSMutableString alloc] initWithString: [_serverURL absoluteString] ];
	[srvURL appendString:@"unlock.php"];

	DBTable* db = [[[DBTable alloc] initWithURL:[NSURL URLWithString:srvURL]  tableName:_tableName] autorelease];
	[db load];
	[srvURL release];
	//[db release];
	
}

-(BOOL) setSelectedElement:(NSMutableDictionary*) dict
{
	BOOL res = NO;
	
	if(_selectedElement != dict)
	{
		if(_selectedElement)
		{
			//NSLog(@"%@", dict);
			NSString* elementID = [_selectedElement objectForKey:@"id"];
			res = [self unlockElementWithID:elementID];
			[_selectedElement release];
			
		}
		
		_selectedElement = dict;
		
		if(dict)
		{
			[_selectedElement retain];
			NSString* elementID = [_selectedElement objectForKey:@"id"];
			res = [self lockElementWithID:elementID];
		}
	}
	return res;
}



-(NSMutableDictionary*) selectedElement
{
	return _selectedElement;
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
	
	if([elementName isEqualToString:_elementName]) 
	{
		[_elemente addObject:_element];
		//[_element release]; _element = nil;
		
		//[pacientiController addObject:pacient];
	}
	else  
	{
		if(![elementName isEqualToString:_tableName])
		{
			[_element setValue:xmlString forKey:elementName];
			[xmlString release];
			xmlString = [[NSMutableString alloc] init];
			
		}
		else {
			[xmlString release];
			xmlString = nil;
			[parser abortParsing];
		}

	}
	
	
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
	
	if(!xmlString) xmlString = [[NSMutableString alloc] init];
	
	[xmlString appendString:string];
	
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
	
	if([elementName isEqualToString:_tableName])
	{
		if(!_elemente) _elemente = [[NSMutableArray alloc] init];
	}
	else if([elementName isEqualToString:_elementName])
	{
		if(_element) [_element release];
		_element = [[NSMutableDictionary alloc] init];
	}
	
}

-(void)dealloc
{
	
	[_element autorelease];
	_element = nil;
	//[_elemente removeAllObjects];
	[_elemente autorelease];
	_elemente = nil;
	
//	[xmlString release];
	[_selectedElement autorelease];
	
	//[lockedElements removeAllObjects];
	[lockedElements autorelease];
	
	[_tableName autorelease];
	[_elementName autorelease];
	[ _url autorelease];
	[_serverURL autorelease];
	[_postDict autorelease];
	
	//[parser setDelegate:nil];
	//if(parser)[parser release];
	
	[loadTime autorelease];
	[q release];
	
	[super dealloc];
}

@end
